
/**
 *  \file obex_internal.h
 *
 *  Module Internal Header file for OBEX
 */

/*
 *  Copyright (C) 2013. Mindtree Ltd.
 *  All rights reserved.
 */

#ifndef _H_OBEX_INTERNAL_
#define _H_OBEX_INTERNAL_

/* -------------------------------------------- Header File Inclusion */
#include "BT_api.h"
#include "BT_debug.h"

#ifdef OBEX

#include "BT_obex_api.h"
#include "obex.h"

#include "obex_fsm.h"
#include "obex_fsm_engine.h"

#ifdef OBEX_OVER_L2CAP
#include "l2cap.h"
#include "BT_bottom_half.h"
#endif /* OBEX_OVER_L2CAP */


/* -------------------------------------------- OBEX Debug */
#ifndef OBEX_NO_DEBUG
#define OBEX_ERR(...)   BT_debug_error(BT_MODULE_ID_OBEX, __VA_ARGS__)
#else  /* OBEX_NO_DEBUG */
#define OBEX_ERR        BT_debug_null
#endif /* OBEX_NO_DEBUG */

#ifdef OBEX_DEBUG

#define OBEX_TRC(...)   BT_debug_trace(BT_MODULE_ID_OBEX, __VA_ARGS__)
#define OBEX_INF(...)   BT_debug_info(BT_MODULE_ID_OBEX, __VA_ARGS__)

#define OBEX_debug_dump_bytes(data, datalen) BT_debug_dump_bytes(BT_MODULE_ID_OBEX, (data), (datalen))

#else  /* OBEX_DEBUG */

#define OBEX_TRC        BT_debug_null
#define OBEX_INF        BT_debug_null

#define OBEX_debug_dump_bytes(data, datalen)

#endif /* OBEX_DEBUG */


/* -------------------------------------------- Type Definitions */
/*@{*/

/**
 *  @name OBEX version number
 *  Major number is upper nibble
 *  Minor number is lower nibble
 */
#define OBEX_VERSION                   0x10

/*@}*/


/*@{*/

/**
 *  @name The two high order bits of the OBEX headers are used to indicate
 *  the Header Encoding as below. The lower 6 bits are used
 *  to indicate the meaning of the header.
 */
#define OBEX_UNICODE                    0x00
#define OBEX_BYTE_SEQ                   0x40
#define OBEX_BYTE                       0x80
#define OBEX_4BYTE                      0xC0

/* Obex data type lengths */
#define OBEX_BYTE_LENGTH                1
#define OBEX_4BYTE_LENGTH               4

#define OBEX_HIGH_ORDER_2BITS_MASK      0xC0

/* Length of common OBEX operation headers */
#define OBEX_OPCODE_HDR_LEN             3

 /* Additional length for connect = (7 - OBEX_OPCODE_HDR_LEN) */
#define OBEX_CONNECT_HDR_EXTRA_LEN      4

/* Additional length for setpath =  (5 - OBEX_OPCODE_HDR_LEN) */
#define OBEX_SETPATH_HDR_EXTRA_LEN      2

/* Length of Connect Pkt */
#define OBEX_OPCODE_CONNECT_PKT_LEN     7

/* Length of Setpath Pkt */
#define OBEX_OPCODE_SETPATH_PKT_LEN     5

/* OBEX Tranport type: RFCOMM = 0x01, L2CAP = 0x02 */
#define OBEX_TRANS_RFCOMM            0x01
#define OBEX_TRANS_L2CAP             0x02

/* OBEX Session current mode */
#define OBEX_READ                    0x01
#define OBEX_WRITE                   0x02

#ifdef OBEX_ENH_SUPPORT
/* Length of ACTION Pkt HDR */
#define OBEX_OPCODE_ACTION_PKT_LEN      5
#endif /* OBEX_ENH_SUPPORT */

/* Length of Tag and Length used in TLV scheme */
#define OBEX_TLV_TAG_SIZE               OBEX_BYTE_LENGTH
#define OBEX_TLV_LENGTH_SIZE            OBEX_BYTE_LENGTH

/* Max value of flag in SetPath */
#define OBEX_SETPATH_FLAG_MAX_VALUE     3

/* Length of buffer for Authentication */
#define OBEX_AUTH_BUF_LEN               16

/*@}*/


#ifdef OBEX_OVER_L2CAP
#define OBEX_L2CAP_INVALID_CID           0x0000

#define OBEX_L2CAP_PROCEDURE_PENDING     0x0001

#define OBEX_L2CAP_STATE_IDLE            0x00000000
#define OBEX_L2CAP_STATE_CONNECTING      0x00000001
#define OBEX_L2CAP_STATE_CONNECTED       0x00000002
#define OBEX_L2CAP_STATE_CONFIGURING     0x00000004
#define OBEX_L2CAP_STATE_CONFIGURED      0x00000008
#define OBEX_L2CAP_STATE_PCONFIGURED     0x00000010
#define OBEX_L2CAP_STATE_DISCONNECTING   0x00000020
#endif /* OBEX_OVER_L2CAP */


#ifdef OBEX_SUPPORT_RELIABLE_SSN
#define OBEX_SSN_STATE_CLOSED            0x00
#define OBEX_SSN_STATE_OPEN              0x01
#define OBEX_SSN_STATE_SUSPENDED         0x02
#endif /* OBEX_SUPPORT_RELIABLE_SSN */

/*@{*/

/**
 *  @name OBEX States:
 *  State transition of obex session depends upon the current state
 *  and the recent event
 */

/**
 *  OBEX states - Common to both Client and Server
 */

/* OBEX FSM Un-initstate */
#define OBEX_STATE_UNINITIALIZED               0x00

/*@}*/

/*@{*/

/* OBEX Operation types for use in state validation */
#define OBEX_OP_TYPE_REQUEST                   0xA0
#define OBEX_OP_TYPE_RESPONSE                  0xA1
#define OBEX_OP_TYPE_EVENT_IND                 0xA2
#define OBEX_OP_TYPE_EVENT_CFM                 0xA3

/*@}*/


/*@{*/

/* BIT Masks for Connect and Setpath, Action Flags*/
#define OBEX_BIT_MASK_0                        0x01 /* Used for Connect */
#define OBEX_BIT_MASK_1                        0x02 /* Setpath (Backup flag) */
#define OBEX_BIT_MASK_2                        0x04 /* Setpath (Dont create) */

#ifdef OBEX_ENH_SUPPORT
#define OBEX_BIT_MASK_3                        0x08 /* ACTION */
#define OBEX_BIT_MASK_4                        0x10 /* ACTION */
#endif /* OBEX_ENH_SUPPORT */
/*@}*/

#define OBEX_ACCESS_STATE(i)    (obex_inst[i].state)

#define OBEX_SET_STATE(i, s)\
    (OBEX_ACCESS_STATE((i)) =  (s))

#define OBEX_GET_STATE(i, s)\
    ((s) = OBEX_ACCESS_STATE((i)))

#define OBEX_L2CAP_IS_STATE(ssn, st)   \
    ((ssn).l2cap_handle.state & (st))? BT_TRUE: BT_FALSE

#define OBEX_L2CAP_SET_STATE(ssn, st)   \
    (ssn).l2cap_handle.state = (st)

#define OBEX_L2CAP_MASK_STATE(ssn, st)   \
    (ssn).l2cap_handle.state |= (st)

#define OBEX_L2CAP_UNMASK_STATE(ssn, st)   \
    (ssn).l2cap_handle.state &= ~(st)

#define OBEX_SET_LSRM(handle, value) \
    obex_inst[(handle)].srm |= ((value) & 0x01);

#define OBEX_SET_RSRM(handle, value) \
    obex_inst[(handle)].srm |= ((value) & 0x02);

#define OBEX_SET_SRMP(handle, value) \
    obex_inst[(handle)].srm |= (((value) << 4) & 0xF0);

/* -------------------------------------------- Structure/Data Types */
/*@{*/

struct obex_xmd5context
{
    UINT32 buf[4];
    UINT32 bytes[2];
    UINT32 in[16];
};

/**
 *  @name Union of the header values used in the Object header
 */
typedef union header_data
{
    UCHAR    *value;
    UINT32   four_byte;
    UCHAR    byte;

}HEADER_DATA;

/*@}*/


#ifdef OBEX_OVER_L2CAP

typedef struct _OBEX_L2CAP_HANDLE
{
    /* L2CAP local PSM registered for the session */
    UINT16 lpsm;

    /* L2CAP remote PSM over the session */
    UINT16 rpsm;

    /* L2CAP Channel Identifier */
    UINT16 cid;

    /* L2CAP OutMTU configured for the channel */
    UINT16 omtu;

    /* L2CAP InMTU assigned for the channel */
    UINT16 imtu;

    /* L2CAP channel state */
    UINT16 state;

    /* L2CAP channel configuration state */
    UCHAR config;

    /* Channel Initiator Indicator */
    UCHAR initiator;

    /* Remote BD Address */
    UCHAR bd_addr[BT_BD_ADDR_SIZE];

} OBEX_L2CAP_HANDLE;

typedef struct _OBEX_BH_PARAMS
{
    /* Data pointer to be passed into BH */
    UCHAR * data;

    /* User information blob */
    void * ubuf;

    /* Data length */
    UINT16 datalen;

    /* User information blob size */
    UINT16 ubuf_size;

    /* OBEX Handle */
    OBEX_HANDLE handle;

} OBEX_BH_PARAMS;
#endif /* OBEX_OVER_L2CAP */


/* Members required for Reliable Session */
#ifdef OBEX_SUPPORT_RELIABLE_SSN
typedef struct obex_relssn
{
    /* Session ID */
    UCHAR id[OBEX_RELIABLE_SSN_ID_LEN];

    /* Session Nonce for remote device. Max 16 octets in length */
    UCHAR rnonce[OBEX_RELIABLE_SSN_NONCE_MAXLEN];

    /* Session Nonce for local device. Can be 4 octets to 16 octets in length */
    UCHAR lnonce[OBEX_RELIABLE_SSN_NONCE_LEN];

    /* Local device address */
    UCHAR laddr[BT_BD_ADDR_SIZE];

    /* Remote device address */
    UCHAR raddr[BT_BD_ADDR_SIZE];

    /*
     * Suspend Timeout - 4 byte value.
     * Time after which session is considered closed.
     * Default timeout is Infinity (0xFFFFFFFF)
     */
    UINT32 to;

    /* Remote device session nonce length */
    UCHAR rnoncelen;

    /* Session Opcode currently in progress */
    UCHAR opcode;

    /* Sequence Number */
    UCHAR seqn;

    /* Next Sequence Number */
    UCHAR nseqn;

    /*
     * Transport Quality Preference. Can have the following values -
     * TRANSPORT_NON_RELIABLE       - 0x00
     * TRANSPORT_PREF_RELIABLE      - 0x01
     * TRANSPORT_STRICT_RELIABLE    - 0x02
     */
    UCHAR qos;

    /* State of the session */
    UCHAR state;

} OBEX_RELSSN;
#endif /* OBEX_SUPPORT_RELIABLE_SSN */

/*@{*/

/**
 *  @name Data Structures for handling the OBEX objects
 */

/*
 *  Sturcture used to store all the necessary information required to
 *  identify a unique obex session.
 */

typedef struct obex_session
{
    /* Callback for the session */
    OBEX_NOTIFY_CB obex_notify_cb;

    /* Current state of a obex session */
    UINT32 state;

    /* Previous state of a obex session */
    UINT32 prev_state;

    /* Version of remote obex entity connected */
    UCHAR version;

    /* Flags used in Connect & Setpath */
    UCHAR flags;

    /* Operation Mode of the session: it indicates client or server  */
    UCHAR role;

    /* To indicate if the session is to be unregistered */
    UCHAR reset;

    /* Current acitve transaction 0x01 -> write, 0x02 -> read */
    UCHAR mode;

    /* Tx. Buffer */
    UCHAR * tx_buffer;

    /* Rx. Buffer */
    UCHAR * rx_buffer;

    /* Rx. Buffer head pointer */
    UCHAR * rx_buffer_head;

    /* Packet length for a transaction */
    UINT16 packet_len;

    /* Actual Packet length present */
    UINT16 transaction_len;

    /* Max. OBEX Tx. packet len */
    UINT16 max_tx_len;

    /* Max. OBEX Rx. packet len */
    UINT16 max_rx_len;

    /* Temporary packet header during transactions */
    UCHAR header[7]; /* TODO: Make Macro */

    /* Temporary packet header length during transactions */
    UINT16 header_len;

    /* Opcode of a transaction */
    UCHAR opcode;

    /* Response code of a transaction */
    UCHAR rsp_code;

#ifdef RFCOMM
    /* RFCOMM connection handle */
    RFCOMM_HANDLE rfcomm_handle;
#endif /* RFCOMM */

#ifdef OBEX_OVER_L2CAP
    /* L2CAP connection handle */
    OBEX_L2CAP_HANDLE l2cap_handle;

    /* 0x01 = RFCOMM 0X02 = L2CAP*/
    UCHAR trans_type;

    /*
     * Local Single Response Mode information mask
     *
     * BIT0: Local SRM header present
     * BIT1: Local SRM header value (b0)
     * BIT2: Local SRM header value (b1)
     * BIT3: Reserved
     * BIT4: Local SRMP header present
     * BIT5: Local SRMP header value (b0)
     * BIT6: Local SRMP header value (b1)
     * BIT7: Reserved
     */
    UCHAR lsrm;

    /*
     * Remote Single Response Mode information mask
     *
     * BIT0: Remote SRM header present
     * BIT1: Remote SRM header value (b0)
     * BIT2: Remote SRM header value (b1)
     * BIT3: Reserved
     * BIT4: Remote SRMP header present
     * BIT5: Remote SRMP header value (b0)
     * BIT6: Remote SRMP header value (b1)
     * BIT7: Reserved
     */
    UCHAR rsrm;

#endif /* OBEX_OVER_L2CAP */

    /* Handling Fragmented Header */
#ifdef OBEX_FRAGMENTED_HDR_SUPPORT
    /*
     * obex_hdr[0] -> Length of the partial header
     * obex_hdr[1] -> Type
     * obex_hdr[2] and obex_hdr[3] -> OBEX packet length
     */
    UCHAR obex_hdr[4];
#endif /* OBEX_FRAGMENTED_HDR_SUPPORT */

#ifdef OBEX_SUPPORT_RELIABLE_SSN
    OBEX_RELSSN ssn;
#endif /* OBEX_SUPPORT_RELIABLE_SSN */
    /* Remote Bluetooth Device Handle for OBEX transport Channel. */
    DEVICE_HANDLE     dev_handle;

} OBEX_SESSION;

/*@}*/

typedef struct _OBEX_REQRSP_PARAMS
{
    OBEX_OBJ_HEADER * obj_hdr;

    UINT32 flags;

    UINT16 num_hdr;

    UCHAR opcode;

    UCHAR rsp_code;

} OBEX_REQRSP_PARAMS;

typedef struct _OBEX_EVENT_MAP
{
    UCHAR obex_request;

    UCHAR request;

} OBEX_EVENT_MAP;

/* -------------------------------------------- Macros */

#define OBEX_LOCK()           BT_MUTEX_LOCK(obex_mutex, OBEX)
#define OBEX_UNLOCK()         BT_MUTEX_UNLOCK(obex_mutex, OBEX)
#define OBEX_LOCK_VOID()      BT_MUTEX_LOCK_VOID(obex_mutex, OBEX)
#define OBEX_UNLOCK_VOID()    BT_MUTEX_UNLOCK_VOID(obex_mutex, OBEX)

/*@{*/

/**
 *  @name Macros used by obex for BT_os APIs
 */

#define obex_malloc       BT_alloc_mem
#define obex_realloc      realloc
#define obex_memset       BT_mem_set
#define obex_memcpy       BT_mem_copy
#define obex_free         BT_free_mem
#define obex_memcmp       BT_mem_cmp

/*@}*/


/**
 *  r = a - b, if a > b
 *  r = 0, if a <= b
 */
#define obex_safe_subtract(a, b, r)                       \
        {                                                 \
            if ((a) <= (b))                               \
            {                                             \
                r = 0;                                    \
            }                                             \
            else                                          \
            {                                             \
                r = (a) - (b);                            \
            }                                             \
        }

#define offset_data(req_code, op_mode, data, datalen)     \
{                                                         \
    if (OBEX_CONNECT_OP == req_code)                      \
    {                                                     \
        data += OBEX_OPCODE_CONNECT_PKT_LEN;              \
        obex_safe_subtract                                \
        (                                                 \
            datalen,                                      \
            OBEX_OPCODE_CONNECT_PKT_LEN,                  \
            datalen                                       \
        );                                                \
    }                                                     \
    else                                                  \
    {                                                     \
        data += OBEX_OPCODE_HDR_LEN;                      \
        obex_safe_subtract                                \
        (                                                 \
            datalen,                                      \
            OBEX_OPCODE_HDR_LEN,                          \
            datalen                                       \
        );                                                \
    }                                                     \
    if ((OBEX_CLIENT_ROLE == op_mode) &&                  \
       (OBEX_SETPATH_OP == req_code))                     \
    {                                                     \
        data += OBEX_SETPATH_HDR_EXTRA_LEN;               \
        obex_safe_subtract                                \
        (                                                 \
            datalen,                                      \
            OBEX_SETPATH_HDR_EXTRA_LEN,                   \
            datalen                                       \
        );                                                \
    }                                                     \
}

#ifdef OBEX_OVER_L2CAP
#define OBEX_L2CAP_SET_HANDLE(hdl, bd, l_psm, r_psm, mtu) \
        (hdl)->lpsm = (l_psm); \
        (hdl)->rpsm = (r_psm); \
        (hdl)->imtu = (mtu); \
        BT_COPY_BD_ADDR((hdl)->bd_addr, (bd));

#define OBEX_L2CAP_RESET_HANDLE(hdl) \
        (hdl)->lpsm = 0x0000; \
        (hdl)->rpsm = 0x0000; \
        (hdl)->imtu = 0x0000; \
        (hdl)->omtu = 0x0000; \
        (hdl)->config = 0x00; \
        (hdl)->cid = OBEX_L2CAP_INVALID_CID; \
        (hdl)->state = OBEX_L2CAP_STATE_IDLE; \
        (hdl)->initiator = BT_FALSE; \
        BT_mem_set ((hdl)->bd_addr, 0x00, BT_BD_ADDR_SIZE);

#endif /* OBEX_OVER_L2CAP */


/*@}*/


/* -------------------------------------------- Function Declarations */
/*@{*/

/**
 *  @name Functions internal to obex module
 */

/* Function to handle obex sessions */

void obex_clear_session
     (
         OBEX_SESSION * obex_session
     );

#ifdef RFCOMM
/* CallBack function Registered with RFCOMM */
API_RESULT obex_rfcomm_callback
           (
               /* IN */ UCHAR           event_type,
               /* IN */ RFCOMM_HANDLE * handle,
               /* IN */ UINT16          result,
               /* IN */ UCHAR         * data,
               /* IN */ UINT16          datalen
           );
#endif /* RFCOMM */

/* Function for MD5 algorithm */
void obex_md5
     (
         /* OUT */ void *   dest,
         /* IN */  void *   orig,
         /* IN */  UINT32   len
     );

void obex_pack_tx_headers
     (
         OBEX_HANDLE handle,
         UCHAR * buffer,
         OBEX_OBJ_HEADER * obj_hdr,
         UINT16 num_hdrs
     );

API_RESULT obex_send
           (
               OBEX_HANDLE handle,
               OBEX_OBJ_HEADER * obj_hdrs,
               UINT16 num_hdrs
           );

API_RESULT obex_process_transport_read
           (
               /* IN */  UCHAR index,
               /* IN */  UINT16 result,
               /* IN */  UCHAR * data,
               /* IN */  UINT16 datalen,
               /* OUT */ UINT16 * consumed
           );

void obex_get_session_data
     (
         OBEX_HANDLE handle,
         UCHAR ** data,
         UINT16 * datalen
     );

UCHAR obex_get_fsm_request_id (UCHAR request);

/*@}*/

#ifdef OBEX_AL
/* For the Adaptation Layer for Older OBEX APIs */
void obex_al_init (void);
void obex_al_bt_init (void);
void obex_al_bt_shutdown (void);
#endif /* OBEX_AL */

#ifdef OBEX_OVER_L2CAP

/* L2CAP Callbacks */
API_RESULT obex_l2ca_connect_ind
           (
               /* IN */  DEVICE_HANDLE *  handle,
               /* IN */  UINT16     lcid,
               /* IN */  UINT16     psm
           );

API_RESULT obex_l2ca_connect_cnf
           (
               /* IN */  DEVICE_HANDLE *  handle,
               /* IN */  UINT16     lcid,
               /* IN */  UINT16     result,
               /* IN */  UINT16     status
           );

API_RESULT obex_l2ca_disconnect_ind
           (
               /* IN */  UINT16    lcid
           );

API_RESULT obex_l2ca_disconnect_cnf
           (
               /* IN */  UINT16    lcid,
               /* IN */  UINT16    result
           );

API_RESULT obex_l2ca_config_ind
           (
               /* IN */  UINT16                   lcid,
               /* IN */  L2CAP_CONFIG_OPTION *    config_option
           );

API_RESULT obex_l2ca_config_cnf
           (
               /* IN */  UINT16                   lcid,
               /* IN */  UINT16                   result,
               /* IN */  L2CAP_CONFIG_OPTION *    config_option
           );

API_RESULT obex_l2cap_procedure_complete
           (
               UINT16    ssn_id
           );

API_RESULT obex_l2ca_data_read_ind
           (
               /* IN */  UINT16     lcid,
               /* IN */  UCHAR *    data,
               /* IN */  UINT16     datalen
           );

API_RESULT obex_l2ca_tx_flow_ind
           (
               /* IN */  UINT16   lcid,
               /* IN */  UCHAR    flow
           );

API_RESULT obex_l2ca_get_fec_params
           (
               UINT16              lcid,
               L2CAP_FEC_OPTION    * fec_ptr
           );

void obex_l2cap_config_complete
     (
         /* IN */  UCHAR    s_index,
         /* IN */  UCHAR    state
     );

#endif /* OBEX_OVER_L2CAP */

UINT16 obex_get_hdrs_len
      (
          OBEX_OBJ_HEADER * obj_hdr,
          UINT16 num_hdrs
#ifdef OBEX_OVER_L2CAP
          ,
          UCHAR trans_type
#endif /* OBEX_OVER_L2CAP */
      );

#ifdef OBEX_OVER_L2CAP
API_RESULT obex_get_srm_status
           (
               OBEX_HANDLE * handle,
               UCHAR device,
               UCHAR * value
           );
API_RESULT obex_get_srmp_status
           (
               OBEX_HANDLE * handle
           );
#endif /* OBEX_OVER_L2CAP */

void obex_notify_session
     (
         UCHAR   * index,
         UCHAR     event,
         UINT16    result,
         UCHAR   * data,
         UINT16    datalen
     );

#ifdef OBEX_SUPPORT_RELIABLE_SSN
void obex_session_init
     (
         /* OUT */ OBEX_RELSSN * ssn
     );

void obex_pack_session_params
     (
         /* IN */  OBEX_SESSION * obex_session,
         /* IN */  OBEX_OBJ_HEADER * tlv,
         /* OUT */ UCHAR * ssn_params,
         /* OUT */ UCHAR * ssn_params_len
     );

void obex_unpack_session_params
     (
         /* IN */  OBEX_RELSSN * ssn,
         /* IN */  UCHAR * pdata,
         /* IN */  UCHAR   datalen
     );
#endif /* OBEX_SUPPORT_RELIABLE_SSN */

/* OBEX MD5 interfaces */
void obex_xmd5init(struct obex_xmd5context * context);
void obex_xmd5update
     (
         struct obex_xmd5context * context,
         UCHAR const * buf, INT32 len
     );
void obex_xmd5final
     (
         UCHAR digest[16],
         struct obex_xmd5context * context
     );

#endif /* OBEX */

#endif /* _H_OBEX_INTERNAL_ */

